package com.fjec.common.util;

import lombok.extern.slf4j.Slf4j;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Optional;

/**
 * 日期处理工具对象，使用LocalDateTime对象
 */
@Slf4j
public class DateUtil {

    /**
     * 默认格式化日期格式
     */
    public static final String DATE_FMT_DEF_PATTERN = "yyyy-MM-dd'T'HH:mm:ss";

    /**
     * LocalDateTime转毫秒时间戳
     *
     * @param localDateTime LocalDateTime
     * @return 时间戳
     */
    public static Long ldt2Milli(LocalDateTime localDateTime) {
        try {
            ZoneId zoneId = ZoneId.systemDefault();
            Instant instant = localDateTime.atZone(zoneId).toInstant();
            return instant.toEpochMilli();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 时间戳转LocalDateTime
     *
     * @param milli 时间戳
     * @return LocalDateTime
     */
    public static LocalDateTime milli2Ldt(long milli) {
        try {
            Instant instant = Instant.ofEpochMilli(milli);
            ZoneId zone = ZoneId.systemDefault();
            return LocalDateTime.ofInstant(instant, zone);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * Date转LocalDateTime
     *
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime date2Ldt(Date date) {
        try {
            Instant instant = date.toInstant();
            ZoneId zoneId = ZoneId.systemDefault();
            return instant.atZone(zoneId).toLocalDateTime();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * LocalDateTime转Date
     *
     * @param localDateTime LocalDateTime
     * @return Date
     */
    public static Date ldt2Date(LocalDateTime localDateTime) {
        try {
            ZoneId zoneId = ZoneId.systemDefault();
            ZonedDateTime zdt = localDateTime.atZone(zoneId);
            return Date.from(zdt.toInstant());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 获取当前秒
     *
     * @return
     */
    public static Long getCurrentSecond() {
        return Instant.now().getEpochSecond();
    }

    /**
     * 获取当前毫秒
     *
     * @return
     */
    public static Long getCurrentMilli() {
        return Instant.now().toEpochMilli();
    }

    /**
     * 使用年月日时分秒创建LocalDateTime
     *
     * @param year
     * @param month
     * @param day
     * @param hour
     * @param minute
     * @param second
     * @return
     */
    public static LocalDateTime parseLdt(Integer year, Integer month, Integer day, Integer hour, Integer minute, Integer second) {
        year = Optional.ofNullable(year).orElse(1971);
        month = Optional.ofNullable(month).orElse(1);
        day = Optional.ofNullable(day).orElse(1);
        hour = Optional.ofNullable(hour).orElse(0);
        minute = Optional.ofNullable(minute).orElse(0);
        second = Optional.ofNullable(second).orElse(0);
        return LocalDateTime.of(year, month, day, hour, minute, second);
    }

    /**
     * 使用年月日创建LocalDateTime，创建出的对象时分秒全部为0
     *
     * @param year
     * @param month
     * @param day
     * @return
     */
    public static LocalDateTime parseLdt(Integer year, Integer month, Integer day) {
        return DateUtil.parseLdt(year, month, day, null, null, null);
    }

    /**
     * 解析字符串为LocalDateTime，按照pattern格式
     *
     * @param strDate
     * @param pattern 必须有时分秒
     * @return
     */
    public static LocalDateTime parseLdt(String strDate, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.from(formatter.parse(strDate));
    }

    /**
     * 使用年月日时分秒创建Date
     *
     * @param year
     * @param month
     * @param day
     * @param hour
     * @param minute
     * @param second
     * @return
     */
    public static Date parseDate(Integer year, Integer month, Integer day, Integer hour, Integer minute, Integer second) {
        LocalDateTime ldt = DateUtil.parseLdt(year, month, day, hour, minute, second);
        return DateUtil.ldt2Date(ldt);
    }

    /**
     * 使用年月日创建Date，创建出的对象时分秒全部为0
     *
     * @param year
     * @param month
     * @param day
     * @return
     */
    public static Date parseDate(Integer year, Integer month, Integer day) {
        return DateUtil.parseDate(year, month, day, null, null, null);
    }

    /**
     * 解析字符串为Date，按照pattern格式
     *
     * @param strDate
     * @param pattern 必须有时分秒
     * @return
     */
    public static Date parseDate(String strDate, String pattern) {
        return DateUtil.ldt2Date(DateUtil.parseLdt(strDate, pattern));
    }

    /**
     * 时间增加
     *
     * @param date
     * @param unit  增加单位，支持年、月、日、时、分、秒，详见ChronoUnit
     * @param value
     * @return
     */
    public static Date timePlus(Date date, ChronoUnit unit, Integer value) {
        LocalDateTime ldt = DateUtil.date2Ldt(date);
        switch (unit) {
            case YEARS:
                ldt.plusYears(value);
                break;
            case MONTHS:
                ldt.plusMonths(value);
                break;
            case DAYS:
                ldt.plusDays(value);
                break;
            case HOURS:
                ldt.plusHours(value);
                break;
            case MINUTES:
                ldt.plusMinutes(value);
                break;
            case SECONDS:
                ldt.plusSeconds(value);
                break;
        }
        return DateUtil.ldt2Date(ldt);
    }

    /**
     * 减少时间
     *
     * @param date
     * @param unit  增加单位，支持年、月、日、时、分、秒，详见ChronoUnit
     * @param value
     * @return
     */
    public static Date timeMinus(Date date, ChronoUnit unit, Integer value) {
        LocalDateTime ldt = DateUtil.date2Ldt(date);
        switch (unit) {
            case YEARS:
                ldt.minusYears(value);
                break;
            case MONTHS:
                ldt.minusMonths(value);
                break;
            case DAYS:
                ldt.minusDays(value);
                break;
            case HOURS:
                ldt.minusHours(value);
                break;
            case MINUTES:
                ldt.minusMinutes(value);
                break;
            case SECONDS:
                ldt.minusSeconds(value);
                break;
        }
        return DateUtil.ldt2Date(ldt);
    }

    /**
     * 格式化日期输出
     *
     * @param ldt
     * @param pattern
     * @return
     */
    public static String format(LocalDateTime ldt, String pattern) {
        pattern = Optional.ofNullable(pattern).orElse(DATE_FMT_DEF_PATTERN);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return formatter.format(ldt);
    }

    /**
     * 格式化日期输出
     *
     * @param date
     * @param pattern
     * @return
     */
    public static String format(Date date, String pattern) {
        return DateUtil.format(DateUtil.date2Ldt(date), pattern);
    }

    /**
     * 获取当前时间Date
     *
     * @return
     */
    public static Date nowDate() {
        return DateUtil.ldt2Date(LocalDateTime.now());
    }

    /**
     * 获取当前时间LocalDateTime
     *
     * @return
     */
    public static LocalDateTime nowLdt() {
        return LocalDateTime.now();
    }

    /**
     * 返回日期1减日期2的Duration对象 d1-d2
     *
     * @param d1
     * @param d2
     * @return
     */
    public static Duration betweenDate(Date d1, Date d2) {
        return Duration.between(DateUtil.date2Ldt(d2), DateUtil.date2Ldt(d1));
    }

    /**
     * 返回日期1减日期2的值，支持小时、分、毫秒，默认返回毫秒
     * @param d1
     * @param d2
     * @param unit 单位，支持小时、分、毫秒，默认返回毫秒，详见ChronoUnit
     * @return
     */
    public static Long betweenDate(Date d1, Date d2, ChronoUnit unit) {
        Duration duration = DateUtil.betweenDate(d1, d2);
        Long result = 0L;
        switch (unit) {
            case HOURS:
                result = duration.toHours();
                break;
            case MINUTES:
                result = duration.toMinutes();
                break;
//            case NANOS:
//                result = duration.toNanos();
//                break;
            case MILLIS:
            default:
                result = duration.toMillis();
                break;
        }
        return result;
    }

    public static void main(String[] args) {
        Date d1 = DateUtil.nowDate();
        Date d2 = DateUtil.parseDate("2020-08-06 00:00:00", "yyyy-MM-dd HH:mm:ss");

        System.out.println(DateUtil.betweenDate(d1, d2, ChronoUnit.MILLIS));
        System.out.println(DateUtil.betweenDate(d1, d2, ChronoUnit.NANOS));
    }
}
